package com.geek.gkpush.framework.tomcat.protocol;

import org.apache.tomcat.util.threads.ThreadPoolExecutor;

import java.util.concurrent.*;

/**
 * <h1>自定义线程池，主要是解决 Tomcat 线程池被拒后，还有最后一丝丝机会去尝试触发业务执行。</h1><br/>
 *
 * <h1><br/><a href="https://u.geekbang.org/subject/arch3/100614201">Java 业务架构实战营：https://u.geekbang.org/subject/arch3/100614201</a></h1><br/><h1><a href="https://gitee.com/ylimhhmily/BizArchPracticeCamp">Java 业务架构实战营代码地址：https://gitee.com/ylimhhmily/BizArchPracticeCamp</a></h1><br/><h1><a href="https://u.geekbang.org/subject/java4th/1001148?source=app_share">高级 Java 工程体系课 2023 版：https://u.geekbang.org/subject/java4th/1001148?source=app_share</a></h1><br/><h1><a href="https://time.geekbang.org/column/intro/100312101?tab=catalog">Dubbo 源码剖析与实战：https://time.geekbang.org/column/intro/100312101?tab=catalog</a></h1>
 *
 * @author hmilyylimh
 * ^_^
 * @version 0.0.1
 * ^_^
 * @date 2023/9/27 05:37
 */
public class CustomThreadPoolExecutor extends ThreadPoolExecutor {

    public CustomThreadPoolExecutor(int corePoolSize,
                                    int maximumPoolSize,
                                    long keepAliveTime,
                                    TimeUnit unit,
                                    BlockingQueue<Runnable> workQueue,
                                    ThreadFactory threadFactory,
                                    RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
        prestartAllCoreThreads();
    }

    @Override
    public void execute(Runnable command, long timeout, TimeUnit unit) {
        try {
            super.execute(command, timeout, unit);
        } catch (RejectedExecutionException e) {
            // 先触发告警通知，然后触发 run 方法

            // 尝试再次执行，有机会就执行，没机会凉了就凉了
            // 反正到这里已经是濒临将死之际，只要有一口气，那就去尝试一下
            // 但是这么去尝试的话，会有一定的风险的，毕竟这么做是在无限榨干系统的最后一口气
            try {
                command.run();
            } catch (Exception ex) {
                // 如果还是异常了，就不再理会是什么异常，还是抛原来的异常
                throw e;
            }
        }
    }
}